# encoding: utf-8

module Ws

  # class handles all sockets:
  class WSocket
    attr_reader :sockets
    def initialize
      @sockets = Array.new
    end
    def sockets_emit( text = "" )
      for socket in @sockets do
        socket.send text
      end
    end
    def add_socket( socket )
      Rails.logger.debug "Adding socket"
      @sockets.push socket
    end
    def delete_socket( socket )
      @sockets.delete socket
    end
    def delete_by_ws( ws )
      for socket in @sockets do
        if socket.ws == ws
          socket.sendLoggedOutToFriends( @sockets )
          @sockets.delete(socket)
          Rails.logger.debug "Ws deleted successfully."
          return true
        end
      end
      Rails.logger.debug "Ws to delete not found."
      return false
    end
    def find_by_ws( ws )
      for socket in @sockets do
        if socket.ws == ws
          return socket
        end
      end
      Rails.logger.error "Ws not found."
      send_error_to_ws( ws, "Ups, algo salió mal. Tal vez iniciaste sesión en otro lugar." )
      return false
    end
    def find_by_token( token )
      for socket in @sockets do
        if socket.token == token
          return socket
        end
      end
      Rails.logger.error "token not found: #{socket.token}"
      return false
    end
    def find_by_user_id( id )
      for socket in @sockets do
        if socket.user_id == id
          return socket
        end
      end
      # Rails.logger.error "user id not found."
      return false
    end
    def refresh_all_users
      for socket in @sockets do
        unless socket.token_valid?
          Rails.logger.error "token not valid: #{socket.token}"
          send_error_to_ws( socket.ws, "Ups, algo salió mal. Tal vez iniciaste sesión en otro lugar." )
        end
      end
    end
    
    private
      def send_error_to_ws( ws, error_string )
        emitToWs( ws, "error", error_string, -1 )
      end
  end

  # class for each usuario
  class WsUser
    attr_reader :ws, :user, :token
    def initialize( ws )
      @ws = ws
      assign_token 
      find_user
      Rails.logger.debug "User initialized"
    end
    def assign_token
      cookies = @ws.instance_variable_get('@handler').instance_variable_get('@request')['cookie']
      @token = readCookieValue( cookies, "user_id" )
    end
    def find_user
      @user = User.find_by_token @token
      if @user
        Rails.logger.debug "Found user."
      else
        Rails.logger.error "Token doesnt exist"
      end
    end
    def update_position( position )
      @geo = @user.geopositions.new
      @geo.accuracy = position["accuracy"]
      @geo.altitude = position["altitude"]
      @geo.latitude = position["latitude"]
      @geo.longitude = position["longitude"]
      @geo.altitudeAccuracy = position["altitudeAccuracy"]
      @geo.heading = position["heading"]
      @geo.speed = position["speed"]
      @geo.timestamp = position["timestamp"]
      # @geo.save!
      @geo.save(:validate => false)
      Rails.logger.debug "Position updated."
    end
    def sendPositionToFriends( a_sockets )             # find friends and send them an object with your position
      position = {
        :user_id => @user.id,
        :latitude => @geo.latitude,
        :longitude => @geo.longitude
      }
      # Rails.logger.debug "\n\na_sockets: #{a_sockets}"
      for person in a_sockets.sockets do
        # Rails.logger.debug "\n\n\nPERSON: #{person.inspect}"
        if person.user.are_friends?(@user)
          emitToWs( person.ws, "friend_position", nil, 1, position )
        end
      end
      Rails.logger.debug "Position sent to friends"
    end
    def retrieve_friends( a_sockets )
      for person in a_sockets.sockets do
        if person.user.are_friends?(@user)
          position = {
            :user_id => person.user.id,
            :latitude => person.user.last_latitude,
            :longitude => person.user.last_longitude
          }
          emitToWs( @ws, "friend_position", nil, 1, position)
        end
      end
    end
    def sendLoggedOutToFriends( a_sockets )
      for person in a_sockets do
        if person.user.are_friends?(@user)
          friend = {
            :user_id => @user.id
          }
          emitToWs( person.ws, "friend_logged_out", nil, 2, friend)
        end
      end
    end
    def token_valid?
      User.token_valid? @token
    end
    def user_id
      @user.id
    end
  end
end

# to read cookies:
def readCookieValue(cookie_string, name)
  nameEq = name + "="
  ca = cookie_string.split(";")
  Rails.logger.debug "Looking for cookie #{nameEq}"
  (0..(ca.length-1)).each do |i|
    # Rails.logger.debug "Iteration #{i.to_s}."
    c = ca[i]
    # Rails.logger.debug "c value: #{c}"
    while c[0] == ' ' do
      c = c.slice 1, c.length
      # Rails.logger.debug "c sliced. New value: #{c}"
    end
    Rails.logger.debug "this cookie's full text: #{c}"
    if c.include? nameEq
      c_value = c.slice nameEq.length, c.length
      # Rails.logger.debug "COOKIE FOUND:"
      # Rails.logger.debug(c.slice nameEq.length, ca[i].length)
      Rails.logger.debug "Its value is #{c_value}"
      return c_value
    end
  end
  return nil
end

# to process every message recieved from websocket client.
def processMessage(object, ws)
  # token = object["token"]
  case object["type"]
  when "position"
    u = @a_sockets.find_by_ws( ws )
    # Rails.logger.debug "Found user:\n" + u.inspect
    u.update_position( object["position"] )
    u.sendPositionToFriends( @a_sockets )
  end

end

def emitToWs( ws, type, text, code=nil, data=nil )
  obj = {
    :type => type,
    :code => code,
    :text => text,
    :data => data
  }
  ws.send( obj.to_json )
end